#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>

#define CARD_COUNT 54
#define PLAYER_COUNT 3

enum Suit {CLUBS, DIAMONDS, HEARTS, SPADES, JOKER1, JOKER2};

typedef struct{
    unsigned int face;
    enum Suit suit;
}Card;

typedef struct{
    char name[64];
    Card **deck;
    int counts;
}Player;

void InitDeck(Card*, int, bool);
Card** ShuffleDeck(Card*, int);
bool DispatchDeck(Player**, int, Card**, int);
Player** CreatePlayers(int);
void PrintPlayerDeck(Player**, int);
void DestroyPlayers(Player**, int);

int main(void)
{
    Card deck[CARD_COUNT];
    InitDeck(deck, CARD_COUNT - 2, true);

    Card **pShuffledDeck = ShuffleDeck(deck, CARD_COUNT);

    Player **pPlayers = CreatePlayers(PLAYER_COUNT);

    DispatchDeck(pPlayers, PLAYER_COUNT, pShuffledDeck, CARD_COUNT);

    free(pShuffledDeck);
    pShuffledDeck = NULL;

    PrintPlayerDeck(pPlayers, PLAYER_COUNT);

    DestroyPlayers(pPlayers, PLAYER_COUNT);
    
    free(pPlayers);
    pPlayers = NULL;

    return 0;
}

void InitDeck(Card *pDeck, int n, bool useJoker)
{
    int i = 0;

    for (i = 0; i < n; i ++)
    {
        pDeck[i].face = i / 4 + 1;
        pDeck[i].suit = (enum Suit)(i % 4);
    }

    if (useJoker)
    {
        pDeck[i].face = i / 4 + 1;
        pDeck[i].suit = JOKER1;
        pDeck[i+1].face = i / 4 + 2;
        pDeck[i+1].suit = JOKER2;
    }
}

Card **ShuffleDeck(Card *pDeck, int n)
{
    Card **pShuffledDeck = (Card**)malloc(n * sizeof(Card*));
    Card **pDeckItem = (Card**)malloc(n * sizeof(Card*));

    if (pShuffledDeck == NULL || pDeckItem == NULL)
    {
        return NULL;
    }

    for (int i = 0; i < n; ++i)
    {
        pDeckItem[i] = &pDeck[i];
    }

    srand(time(NULL));

    for (int i = 0; i < n; ++i)
    {
        unsigned int idx = rand() % n;
        if (pDeckItem[idx] != NULL)
        {
            pShuffledDeck[i] = pDeckItem[idx];
            pDeckItem[idx] = NULL;
        }
        else
        {
            --i;
        }
    }
    free(pDeckItem);

    return pShuffledDeck;
}

Player** CreatePlayers(int n)
{
    char name[16] = "";

    Player *pPlayers = (Player*)malloc(sizeof(Player) * n);

    if (pPlayers == NULL)
    {
        return NULL;
    }

    for (int i = 0; i < n; i++)
    {
        scanf("%s", name);

        strcpy(pPlayers[i].name, name);
        pPlayers[i].deck = NULL;
        pPlayers[i].counts = 0;
    }

    Player **pPlayer = (Player**)malloc(sizeof(Player*) * n);

    if (pPlayer == NULL)
    {
        return NULL;
    }

    for (int i = 0; i < n; i++)
    {
        pPlayer[i] = &pPlayers[i];
    }

    return pPlayer;
}

bool DispatchDeck(Player** pPlayers, int nPlayerCount, Card** pShuffledDeck, int n)
{
    int cardNums = n / nPlayerCount;
    int cardOvers = n % nPlayerCount;

    for (int i = 0; i < nPlayerCount; i++)
    {
        Card **pPlayerDeck = (Card**)malloc(cardNums * sizeof(Card*));

        if (pPlayerDeck == NULL)
        {
            return false;
        }
        pPlayers[i]->deck = pPlayerDeck;
    }

    for (int i = 0; i < n - cardOvers; ++i)
    {
        Player* pCurrPlayer = pPlayers[i % nPlayerCount];

        pCurrPlayer->deck[pCurrPlayer->counts] = pShuffledDeck[i];
        pCurrPlayer->counts ++;
    }

    return true;
}

void PrintPlayerDeck(Player **pPlayers, int n)
{
    for (int i = 0; i < n; i ++)
    {
        printf("%s: ", pPlayers[i]->name);

        for (int j = 0; j < pPlayers[i]->counts; j ++)
        {
            printf("%d-%d ", pPlayers[i]->deck[j]->face, pPlayers[i]->deck[j]->suit);
        }
        printf("\n");

    }
}


void DestroyPlayers(Player **pPlayers, int n)
{
    for (int i = 0; i < n; i ++)
    {
        free(pPlayers[i]->deck);
        pPlayers[i]->deck = NULL;
        free(pPlayers[i]);
    }
}
